package com.manage.competition.shiro;

import com.manage.competition.redis.KeyPrefix;
import com.manage.competition.redis.LoginRetryKey;
import com.manage.competition.redis.RedisService;
import lombok.Getter;
import lombok.Setter;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * Create with IDEA
 *
 * @Author:Vantcy
 * @Date: Create in 22:01 2019/1/28
 * @Description:
 */
@Getter
@Setter
public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher {

    private static final KeyPrefix RETRY_KEY_PREFIX = LoginRetryKey.getByRetryCount;

    private static final String RETRY_PREFIX = RETRY_KEY_PREFIX.getPrefix();

    /**
     * 自定义密码错误上限
     */
    private final static Integer RETRY_MAX = 3;

    /**
     * 禁止重试时间限制 /秒
     */
    private final static long EXPIRE_TIME = 60 * 1 ;


    @Autowired
    private RedisService redisService;

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws ExcessiveAttemptsException {
        String username = (String)token.getPrincipal();
        Integer retryCount = (Integer) redisService.get(RETRY_PREFIX+username);
        if(retryCount == null) {
            retryCount = 0;
            // 两分钟失效
            redisService.set(RETRY_PREFIX+username, retryCount,EXPIRE_TIME);

        }

        if(retryCount >= RETRY_MAX) {
            throw new ExcessiveAttemptsException("您已连续错误达" + RETRY_MAX + "次以上！请1分钟后再试");
        }

        //调用父类的校验方法
        boolean matches = super.doCredentialsMatch(token, info);
        if(matches) {
            redisService.del(RETRY_PREFIX+username);
        }else {
            //次数递增
            redisService.set(RETRY_PREFIX+username, ++retryCount, EXPIRE_TIME);
            throw new IncorrectCredentialsException("密码错误，已错误" + retryCount + "次，最多错误" + RETRY_MAX + "次");
        }
        return true;
    }
}
